/*
 * Time:20200508
 * Author: youngda
 * QQ:1217882800
 * wechat:19092550573
 * QQ群：824273231
 * 项目示例：通过发送on或off控制开关
 */
const char *mqtt_server = "bemfa.com";                          // 默认，MQTT服务器
const int mqtt_server_port = 9501;                              // 默认，MQTT服务器
#define ID_MQTT "4892bd7fe005ecbbccf35929157ec7e7"              // 修改，你的Client ID
const char *topic = "adada006";                                 // 主题名字，可在巴法云控制台自行创建，名称随意
const char *topicA = "hass954c4f82ab7b33f179386e6c485781e2004"; // 主题名字，可在巴法云控制台自行创建，名称随意
const char *topicB = "hass6b664bf427ab841719114f774e5590e1004"; // 主题名字，可在巴法云控制台自行创建，名称随意

extern WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;

// 灯光函数及引脚定义
void turnOnLed();
void turnOffLed();
const int LedBlink = 2;

// 当升级开始时，打印日志
void update_started()
{
  Serial.println("CALLBACK:  HTTP update process started");
}

// 当升级结束时，打印日志
void update_finished()
{
  Serial.println("CALLBACK:  HTTP update process finished");
}

// 当升级中，打印日志
void update_progress(int cur, int total)
{
  digitalWrite(LedBlink, !digitalRead(LedBlink)); // 切换指示灯状态
  Serial.printf("CALLBACK:  HTTP update process at %d of %d bytes...\n", cur, total);
}

// 当升级失败时，打印日志
void update_error(int err)
{
  Serial.printf("CALLBACK:  HTTP update fatal error code %d\n", err);
}

/**
 * 固件升级函数
 * 在需要升级的地方，加上这个函数即可，例如setup中加的updateBin();
 * 原理：通过http请求获取远程固件，实现升级
 */
void updateBin()
{
  String upUrl = "http://bin.bemfa.com/b/3BcNDg5MmJkN2ZlMDA1ZWNiYmNjZjM1OTI5MTU3ZWM3ZTc=" + topic + ".bin"; // OTA固件链接，请替换为自己的固件链接，如果接收到msg=update，开始执行固件升级

  Serial.println("start update");
  WiFiClient UpdateClient;
  ESPhttpUpdate.onStart(update_started);     // 当升级开始时
  ESPhttpUpdate.onEnd(update_finished);      // 当升级结束时
  ESPhttpUpdate.onProgress(update_progress); // 当升级中
  ESPhttpUpdate.onError(update_error);       // 当升级失败时

  t_httpUpdate_return ret = ESPhttpUpdate.update(UpdateClient, upUrl);
  switch (ret)
  {
  case HTTP_UPDATE_FAILED: // 当升级失败
    Serial.println("[update] Update failed.");
    break;
  case HTTP_UPDATE_NO_UPDATES: // 当无升级
    Serial.println("[update] Update no Update.");
    break;
  case HTTP_UPDATE_OK: // 当升级成功
    Serial.println("[update] Update ok.");
    break;
  }
}

void callback(char *topic, byte *payload, unsigned int length)
{
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  String Mqtt_Buff = "";
  for (unsigned int i = 0; i < length; i++)
  {
    Mqtt_Buff += (char)payload[i];
  }
  Serial.print(Mqtt_Buff);
  Serial.println();

  if (strcmp(topic, topicA) == 0)
  { // 判断topic是否是topicA
    Serial.println(" topicA msg");
    if (Mqtt_Buff == "on")
    {              // 如果接收字符on，亮灯
      turnOnLed(); // 开灯函数
    }
    else if (Mqtt_Buff == "off")
    {               // 如果接收字符off，亮灯
      turnOffLed(); // 关灯函数
    }
  }
  else if (strcmp(topic, topicB) == 0)
  { // 判断topic是否是topicB
    Serial.println(" topicB msg");
    if (Mqtt_Buff == "on")
    {              // 如果接收字符on，亮灯
      turnOnLed(); // 开灯函数
    }
    else if (Mqtt_Buff == "off")
    {               // 如果接收字符off，亮灯
      turnOffLed(); // 关灯函数
    }
  }

  Mqtt_Buff = "";
}

void reconnect()
{
  // Loop until we're reconnected
  while (!client.connected())
  {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect(ID_MQTT))
    {
      Serial.println("connected");

      client.subscribe(topic); // 修改，修改为你的主题
      delay(100);
      client.subscribe(topicA); // 修改，修改为你的主题
      delay(100);
      client.subscribe(topicB); // 修改，修改为你的主题
    }
    else
    {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void SetupBemfa()
{
  pinMode(LedBlink, OUTPUT);
  digitalWrite(LedBlink, HIGH);

  client.setServer(mqtt_server, mqtt_server_port);
  client.setCallback(callback);
}
void loopBemfa()
{
  if (!client.connected())
  {
    reconnect();
  }
  client.loop();
}

// 打开灯泡
void turnOnLed()
{
  Serial.println("turn on light");
  digitalWrite(LedBlink, LOW);
}
// 关闭灯泡
void turnOffLed()
{
  Serial.println("turn off light");
  digitalWrite(LedBlink, HIGH);
}
